﻿package{
	import flash.display.Sprite;
	import flash.text.*;
	import flash.events.*;
	import flash.display.*;
	import flash.geom.*;
	import flash.utils.ByteArray;
	import flash.net.*;
	
	import flash.display.MovieClip;
	import com.lorentz.SVG.display.SVGDocument;
	import com.lorentz.SVG.events.SVGEvent;
	import com.lorentz.processing.ProcessExecutor;
	
	import com.glidecast.common.gcUtil;
	import com.glidecast.common.gcSettings;
	import com.glidecast.common.UploadPostHelper;	
	import com.glidecast.views.Toolbar;
	
	import caurina.transitions.Tweener;	
	
	import com.adobe.images.PNGEncoder;
	
	public class GlideCastView extends Sprite
	{
		private var _model:GlideCastModel;
		private var _controller:GlideCastController;
		
		private var _txt:TextField;
		private var svgDocument:SVGDocument;
		private var staticGraphic:DisplayObject;
		
		private var currentSprite:Sprite;
		
		private var currentBitmap:Bitmap;
		private var pastBitmap:Bitmap;
		
		private var mainToolbar:Toolbar;
		
		public static var TEXTLOADCOMPLETE:String='TextLoadComplete';		
		
		public function GlideCastView(m:GlideCastModel,c:GlideCastController)
		{
			
			_model=m;
			_controller=c;
			_model.addEventListener(GlideCastModel.UPDATE,update);
			_model.addEventListener(GlideCastModel.AUDIOUPDATE, audioUpdate);
			_model.addEventListener(GlideCastModel.GRAPHICUPDATE, graphicUpdate);
			
			addEventListener(Event.ADDED_TO_STAGE, addedToStage);
			addEventListener(GlideCastView.TEXTLOADCOMPLETE, textUpdateComplete);
			
			
		}
		
		protected function addedToStage(event:Event):void 
		{	
			stage.addEventListener(Event.RESIZE, this.fullScreenEvent);
			buildUI();
			createToolbar(0);
		}
		protected function fullScreenEvent(event:Event):void 
		{	
			if (stage.displayState == StageDisplayState.FULL_SCREEN)
			{
				removeChild(mainToolbar);
			}
			else
			{
				createToolbar(1);
			}
			trace("view resized");
			resizeObjects();
			transitionComplete();
		}
		private function resizeObjects():void
		{
			staticGraphic.width=getTargetWidth();
			staticGraphic.height=getTargetHeight();
			/*svgDocument.width=getTargetWidth();
			svgDocument.height=getTargetHeight();
			*/
			svgDocument.scaleX = stage.stageWidth/640;
			svgDocument.scaleY = stage.stageHeight/385;

			
			_txt.width=getTargetWidth();
			_txt.height=getTargetHeight()	
		}
		// This MVC pattern does not require any controller code 
		// to ensure the UI is updated. This is handled via the event controller
		// below.
		private function update(e:Event):void
		{
			// with a built ui (i.e. pieces where stuff goes),
			// use the data in the model to actually display stuff
			updateText();
		}
		private function updateText():void
		{
			if (_model.text != null)
			{
				
					
				currentSprite = new Sprite();
				currentSprite.name = "currentSprite";					
				
				if (_model.templatetype == "html")
				{
					var sheet:StyleSheet = new StyleSheet();
					sheet.parseCSS(_model.style);
					_txt.styleSheet = sheet;
					_txt.htmlText=_model.text;
					dispatchEvent(new Event(GlideCastView.TEXTLOADCOMPLETE));
				}
				else
				{
					// need to add an event listener to wait for SVGEvent.RENDERED
					// that handler needs to call a common hander
					// in that common handler, normal processing can continue.
					svgDocument.parse(_model.text);
				}
			}
			
		}
		private function svgParseCompleteHandler(e:SVGEvent):void 
		{
			//Need to now raise an internal event to go to a common handler.
			dispatchEvent(new Event(GlideCastView.TEXTLOADCOMPLETE));
		}
		/*
			Helper function to pull the bitmap from a sprite's rendered-ness
		*/
		private function getBitmapData(_sp:Sprite):Bitmap
		{
			var currentBitmapData:BitmapData = new BitmapData(getTargetWidth(), getTargetHeight(), true, 0x0);
			currentBitmapData.draw(_sp);
			var tmpBitmap:Bitmap = new Bitmap(currentBitmapData);
			
			return tmpBitmap;
		}
		private function textUpdateComplete(e:Event):void
		{	
			if (_model.templatetype == "html")
				currentSprite.addChild(_txt);
			else
				currentSprite.addChild(svgDocument);
			
			currentBitmap = getBitmapData(currentSprite);
			
			currentBitmap.name = "currentBitmap";

			addChildAt(currentBitmap, 2);
			/*if (pastBitmap!=null)
			{
				
				swapChildren(pastBitmap, currentBitmap);
				tweenAction(pastBitmap, "3D_OUT");								
			}
			pastBitmap = currentBitmap;			
			pastBitmap.name = "pastBitmap";
			*/
			
			tweenAction(getChildAt(3), getChildAt(2), "FADE_OUT");								
			
			var ii:int = 0;
			for ( ii = 0; ii< numChildren;ii++)
			{
			       trace(getChildAt( ii ).name);
			}
			       
			trace(numChildren);
		}
		private function uploadThumb():void
		{
			trace("Sending thumb?");
			if (_model.needThumb)
			{
				trace("Yes, need to send thumb");
				try
				{
					var scale:Number = 0.32;
					var matrix:Matrix = new Matrix();
					matrix.scale(scale, scale);

					var bigBMD:BitmapData = getBitmapData(this).bitmapData;
					var smallBMD:BitmapData = new BitmapData(bigBMD.width * scale, bigBMD.height * scale, true, 0x000000);
					smallBMD.draw(bigBMD, matrix, null, null, null, true);

					var byteArray:ByteArray = PNGEncoder.encode(smallBMD);
					var urlRequest:URLRequest = new URLRequest();
					urlRequest.url = gcSettings.gcGDFThumbUploadUrl();
					urlRequest.contentType = 'multipart/form-data; boundary=' + UploadPostHelper.getBoundary();
					urlRequest.method = URLRequestMethod.POST;
					urlRequest.data = UploadPostHelper.getPostData(_model.gcid + ".png", byteArray);
					urlRequest.requestHeaders.push( new URLRequestHeader( 'Cache-Control', 'no-cache' ) );

					var urlLoader:URLLoader = new URLLoader();
					urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
					urlLoader.load(urlRequest);
				}
				catch(error:Error)
				{
				
				}
			}
		}
		/*
			Directs traffic for different transitions. This could also 
			exist in a static class.
		*/
		private function tweenAction(targetObject:DisplayObject, remainingObject:DisplayObject, _instruction:String):void
		{
			switch (_instruction)
			{
				case "FADE_OUT":
				{
					remainingObject.alpha=0;
					Tweener.addTween(remainingObject, {alpha:1, time:gcSettings.TRANSITION_INTERVAL/1000, transition:"easeOutQuart", onComplete:transitionComplete});
					Tweener.addTween(targetObject, {alpha:0, time:gcSettings.TRANSITION_INTERVAL/1000, transition:"easeOutQuart", onComplete:transitionComplete});
					break;
				}
				case "3D_OUT":
				{
					Tweener.addTween(targetObject, {rotationX:-90, rotationY:90, alpha:0, time:gcSettings.TRANSITION_INTERVAL/1000, transition:"easeOutQuart", onComplete:transitionComplete});
					break;
				}
				case "DIAMOND_IN":
				{
					Tweener.addTween(targetObject, {x:getTargetWidth()/2, y:getTargetHeight()/2, scaleX:0, scaleY:0, alpha:0, time:gcSettings.TRANSITION_INTERVAL/1000, transition:"easeOutQuart", onComplete:transitionComplete});
					break;
				}
			}
		}
		private function transitionComplete():void
		{	
			var i:int = 0;
			for (i=3;i<numChildren; i++)
				removeChildAt(i);
		}
		private function audioUpdate(e:Event):void
		{
			//the sound has been loaded, so now play it.
			_model.audio.play();
		}
		private function graphicUpdate(e:Event):void
		{
			if (_model.graphic.staticGraphic!=null)
			{
				try
				{
					removeChild(staticGraphic);
					trace("removed graphic: " + staticGraphic.name);
				}
				catch(error:Error)
				{
					trace("graphicUpdate error: " + error);
				}
				staticGraphic = _model.graphic.staticGraphic;
				staticGraphic.width=getTargetWidth();
				staticGraphic.height=getTargetHeight();
				//remove prior child if any, then add at bottom of stack.
				addChildAt(staticGraphic, 0);
				
			}
			updateText();			
		}
		private function buildUI():void
		{
			
			ProcessExecutor.instance.initialize(stage);
			ProcessExecutor.instance.percentFrameProcessingTime = 0.9;	
			svgDocument = new SVGDocument();
			svgDocument.addEventListener(SVGEvent.RENDERED, svgParseCompleteHandler);
			
			_txt=new TextField();
			_txt.x = 5;
			_txt.y = 5;
			
			_txt.multiline = true;
			_txt.autoSize = TextFieldAutoSize.LEFT;
			_txt.wordWrap=true;
			
			_txt.width=getTargetWidth();
			_txt.height=getTargetHeight();
			
		}
		/*
			These functions centralize the height and width functions
			for various ui components. Previsouly, stage.stageWidth/Height was
			being used directly, but when the toolbar became required, 
			it meant modifying a number of locations. These functions will ease
			that burden going forward (i.e. you can't count on a fixed width
			or height no more).
		*/
		private function getTargetWidth():int
		{
			if (stage!=null)
			{
				trace("FS Width: " + stage.fullScreenWidth.toString() + ", Width: " + stage.stageWidth.toString());
				if (stage.displayState == StageDisplayState.FULL_SCREEN)
					return stage.fullScreenWidth;
				else
					return stage.stageWidth;
			}
			return 0;
		}
		private function getTargetHeight():int
		{
			if (stage!=null)
			{
				if (stage.displayState == StageDisplayState.FULL_SCREEN)
				{
					return stage.fullScreenHeight;
				}
				else
					return stage.stageHeight-getToolbarHeight();
			}
			return 0;
		}
		private function getToolbarHeight():int
		{
			return 32;
		}
		private function createToolbar(zorder:int):void
		{
			mainToolbar = new Toolbar();
			mainToolbar.name="mainToolbar";
			mainToolbar.x = 0;
			mainToolbar.y = getTargetHeight();
			mainToolbar.width = getTargetWidth();
			mainToolbar.height = getToolbarHeight();
			mainToolbar.addButton("fullscreen", 0, 0, 32, 32, 0xFF0000);
			mainToolbar.addButton("playpause", 90, 0, 32, 32, 0x00FF00);
			mainToolbar.addButton("volumedown", 135, 0, 32, 32, 0x0000FF);
			mainToolbar.addButton("volumemute", 180, 0, 32, 32, 0x0000FF);
			mainToolbar.addButton("volumeup", 225, 0, 32, 32, 0x00FFFF);
			
			mainToolbar.mouseEnabled = false;
			mainToolbar.addEventListener(Toolbar.BUTTONCLICKED, buttonClick);
			addChildAt(mainToolbar, zorder);

			trace("added tb");
		}
		private function buttonClick(event:Event):void 
		{ 
			//I'm going to cheat here and send up a graphic if necessary
			uploadThumb();
			
			trace(mainToolbar.currentButton.name);
			switch (mainToolbar.currentButton.name)
			{
				case "fullscreen":
				{
					stage.scaleMode = StageScaleMode.NO_SCALE;
					stage.align = StageAlign.TOP_LEFT; 
					//fire event to go full screen?
					stage.displayState = StageDisplayState.FULL_SCREEN; 
					break;
				}
				case "playpause":
				{
					// tell the controller to pause?
					if (_model.isPaused)
					{
						_controller.resume();
					}
					else
					{
						_controller.pause();
					}
					break;
				}
				case "volumedown":
				{
					//fire an event? The toolbar CANNOT do real stuff.
					//even this switch statement is wrong.
					_model.audio.volume-=0.1;
					break;
				}
				case "volumeup":
				{
					//fire an event? The toolbar CANNOT do real stuff.
					//even this switch statement is wrong.
					_model.audio.volume+=0.1;
					break;
				}
				case "volumemute":
				{
					//fire an event? The toolbar CANNOT do real stuff.
					//even this switch statement is wrong.
					_model.audio.mute();
					break;
				}
			}
		}
		
	}
	
}
